package com.cty.advice;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

import java.lang.reflect.Modifier;
import java.util.Arrays;

/*
 * 切面获得类信息(返回修饰符，方法名，类名等)
 * 步骤一:形参中加入JoinPoint对象
 * 步骤二:用该对象获得信息
 * 获得方法的返回值信息
 * 获得返回值信息只能在@AfterReturn
 * 在形参列表传入JoinPoint对象和Object接受返回值对象，在注解中加入returning
 * 获得方法的异常信息
 * 在形参列表中加入Throwable对象
 * 在注解中加上throwing
 * 在@AfterThrowing中加入
 * */

@Component
@Aspect
public class MyAdvice {
    /**
     * 切点表达式
     * execution(1 2 3.4.5(6))
     * 1:匹配切点方法的访问修饰符
     * 2:切点方法的返回值类型
     * 如果两个都不具体匹配都用*来代替
     * 只有两个同时不具体时才能使用
     * 3.包的匹配
     * 全包名:com.cty.Service.Impl
     * 可中间模糊匹配
     * com..Impl:匹配com包下的所有Impl子包，无论中间包是否一致
     * com.Service.*:匹配Service下的所有包
     * *..Iml:匹配该项目下的所有Impl包
     * 4.类名
     * 全类名:com.cty.Service.Impl.CalculatorPureImpl
     * com..CalculatorPureImpl:com包下的所有CalculatorPureImpl类
     * *..CalculatorPureImpl:该项目下的所有CalculatorPureImpl类
     * com.cty.Service.Impl.*该包下的所有类
     * 5.方法名
     * 指定该类下的方法
     * com.cty.Service.Impl.CalculatorPureImpl.add 指定了具体类和具体方法
     * com.cty.Service.Impl.CalculatorPureImpl.*该类下的所有方法
     * com..*.add指定com包下的所有类的add方法
     * 6.形参列表
     * (..)参数都可以
     * (String)指定具体的参数列表
     * (int..)指定以int开头的参数的方法后面不考虑
     * (..String)指定以String为结尾的参数前面的参数不考虑
     * (String..int)指定以String为开头int为结尾的参数列表
     * ():表示无参数
     */


    //练习
    /*
    * 1.查询某包某类下，访问修饰符是公有，返回值是int的全部方法
    *        execution(public int xx.xx.*(..))
    *2.查询某包下类中第一个参数是String的方法
    *   execution(* xx.*.*(String..))
    *3.查询全部包下，无参数的方法！
    *   execution(* *..*.*())
    *4.查询com包下，以int参数类型结尾的方法
    *   execution(* com..*.*(..int))
    *5.查询指定包下，Service开头类的私有返回值int的无参数方法
    *  execution(private int xx.xx.Service*.*())
    */

    /*
    * 1.切点表达式的统一管理
    * 在本类中：
    * 定义一个空方法加@Pointcut注解在注解中写入切点表达式，
    * 在使用时调用方法即可(不推荐)
    * 2.统一创建一个类
    * 在类中定义切点表达式方法，
    * 在使用时：调用类的全限定符和方法名即可
    * 注意:这个类也要加入ioc容器
    * */

    @Before("com.cty.pointcut.MyPc.MyPc()")//开始增强
    public void before(JoinPoint joinPoint) {
        //获得类名
        String simpleName = joinPoint.getTarget().getClass().getSimpleName();
        System.out.println("类名" + simpleName);
        //获得方法名
        String name = joinPoint.getSignature().getName();
        System.out.println("方法名" + name);
        //获得外界调用方法传入的形参列表
        Object[] args = joinPoint.getArgs();
        System.out.println("形参列表" + Arrays.toString(args));
        //获得返回修饰符
        int modifiers = joinPoint.getSignature().getModifiers();
        String string = Modifier.toString(modifiers);
        System.out.println("返回修饰符" + string);
    }

    @AfterReturning(value = "com.cty.pointcut.MyPc.MyPc()",/*获得返回值*/ returning = "result")//正常返回增强
    public void afterReturning(JoinPoint jointPoint, Object result) {

    }

    @AfterThrowing(value = "com.cty.pointcut.MyPc.MyPc()",/*获得异常对象*/ throwing = "throwable")//异常增强
    public void afterThrowing(JoinPoint joinPoint, Throwable throwable) {

    }

    @After("com.cty.pointcut.MyPc.MyPc()")//最后增强
    public void after() {

    }


}
